package logic

import (
	rediscache "ahutoj/web/cache/redis"
	"ahutoj/web/dao"
	mysqldao "ahutoj/web/dao/mysqlDao"
	"ahutoj/web/io/constanct"
	"ahutoj/web/io/request"
	"ahutoj/web/io/response"
	"ahutoj/web/mapping"
	"ahutoj/web/middlewares"
	"ahutoj/web/models"
	originJudged "ahutoj/web/service/originJudge/originjudged"
	"ahutoj/web/utils"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/oauth2"
)

func CheckLogin(c *gin.Context, req *request.LoginReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	user := dao.User{}
	if req.Email != "" {
		user.Email = req.Email
		ok := models.IsUserExistByEmail(c, &user)
		if !ok {
			return constanct.AUTH_LOGIN_UIDNotExistCode, errors.New("用户不存在")
		}
		err := models.FindUserByEmail(c, &user)
		if err != nil {
			logger.Errorf("call FindUserByEmail failed,UID=%v err=%v", req.Email, err.Error())
			return constanct.ServerErrorCode, err
		}
	} else {
		user.UID = req.UID
		if ok := models.IsUserExistByUID(c, &user); !ok {
			return constanct.AUTH_LOGIN_UIDNotExistCode, errors.New("用户不存在")
		}
		if err := models.FindUserByUID(c, &user); err != nil {
			logger.Errorf("call FindUserByEmail failed,UID=%v err=%v", req.Email, err.Error())
			return constanct.ServerErrorCode, err
		}
	}
	if req.Pass != "" {
		if ok := models.EqualPassWord(c, &user, req.Pass); !ok {
			return constanct.AUTH_LOGIN_PASSERRORCode, errors.New("pass error")
		}
	} else {
		var (
			ret string
			err error
		)
		if ret, err = rediscache.GetEmailLoginFromRDB(c, req.Email); err != nil {
			logger.Errorf("call GetEmailRegisterFromRDB failed,err=%s", err.Error())
			return constanct.ServerErrorCode, errors.New("get email login from rdb failed")
		}
		if ret != "1" {
			return constanct.AUTH_NOT_EMAIL_VERIFY, errors.New("email is not verify")
		}
		if err := rediscache.DelEmailRegisterToRDB(c, req.Email); err != nil {
			logger.Errorf("call DelEmailRegisterToRDB failed,err=%s", err.Error())
			return constanct.ServerErrorCode, errors.New("del email register from rdb failed")
		}
	}
	token, err := middlewares.GetToken(c, user.UID)
	if err != nil {
		logger.Errorf("call GetToken failed, err=%s", err.Error())
		return constanct.AUTH_LOGIN_TokenBuildCode, errors.New("get token failed")
	}
	permission, err := mysqldao.SelectPermissionByUID(c, user.UID)
	if err != nil {
		logger.Errorf("call SelectPermissionByUID failed,err=%v", err.Error())
		return constanct.ServerErrorCode, errors.New("get permission failed")
	}
	return response.LoginResp{
		Response:      response.CreateResponse(constanct.SuccessCode),
		Token:         token,
		Uname:         user.Uname,
		PermissionMap: mapping.PermissionToBitMap(permission),
		UID:           user.UID,
	}, nil
}

func DoResiger(c *gin.Context, req *request.User) (interface{}, error) {
	logger := utils.GetLogInstance()
	user := dao.User{
		UID:     strings.TrimSpace(req.UID),
		Uname:   req.Uname,
		Pass:    req.Pass,
		School:  req.School,
		Classes: req.Classes,
		Major:   req.Major,
		Email:   strings.TrimSpace(req.Email),
	}
	//检测用户合法性
	//查看用户账号是否存在
	exist := models.IsUserExistByUID(c, &user)
	if exist {
		return response.CreateResponse(constanct.AUTH_REGISTER_UIDExistCode), nil
	}
	// 创建用户
	err := models.CreateUser(c, &user)
	if err != nil {
		logger.Errorf("call CreateUser failed,err=%s", err.Error())
		return response.CreateResponse(constanct.AUTH_REGISTER_FAILED), nil
	}
	// 获取token
	token, err := middlewares.GetToken(c, req.UID)
	if err != nil {
		logger.Errorf("call GetToken failed, err=%s", err.Error())
		return response.CreateResponse(constanct.AUTH_REGISTER_TokenBuildCode), nil
	}
	permission, err := mysqldao.SelectPermissionByUID(c, user.UID)
	if err != nil {
		return nil, err
	}
	// 4、返回注册成功的信息给用户
	return response.RegisterResp{
		Response:      response.CreateResponse(constanct.SuccessCode),
		Token:         token,
		Uname:         user.Uname,
		PermissionMap: mapping.PermissionToBitMap(permission),
		UID:           user.UID,
	}, nil
}

func GetUserInfo(c *gin.Context, req *string) (interface{}, error) {
	user := dao.User{
		UID: *req,
	}
	exist := models.IsUserExistByUID(c, &user)
	if !exist {
		return response.CreateResponse(constanct.USER_INFO_UIDNotExistCode), nil
	}
	models.FindUserByUID(c, &user)
	userResp := response.CreateUserResp(&user)
	if _, ok := middlewares.GetConn(*req); ok {
		userResp.Status = constanct.Online
	}
	return &userResp, nil
}

func GetUserStatusList(c *gin.Context, req *request.GetListReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	m := middlewares.GetAllConn()
	if len(m) <= 0 {
		logger.Info("No one online")
		return response.CreateResponse(constanct.SuccessCode), nil
	}
	ret := make([]string, 0, len(m))
	for k := range m {
		ret = append(ret, k)
	}

	start := (req.Page - 1) * req.Limit
	end := start + req.Limit
	if start > len(ret) {
		start = len(ret)
	}
	if end > len(ret) {
		end = len(ret)
	}

	pagedRet := ret[start:end]
	return response.UserStatusListResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		UIDs:     &pagedRet,
		Count:    len(m),
	}, nil
}

func GetUserSolutionList(ctx *gin.Context, req *request.GetUserSolutionListReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	resp, err := mysqldao.SelectUserSolutionList(ctx, req.UID, req.Page, req.Limit)
	if err != nil {
		logger.Errorf("call SelectUserSolutionList failed, req=%+v,err=%s", utils.Sdump(req), err.Error())
		return nil, err
	}
	solutions := make([]response.GetUserSolutionListItem,len(*resp))
	for idx, item := range *resp {
		solutions[idx]= response.GetUserSolutionListItem{
			SID:        item.SID,
			PID:        item.PID,
			Title:      item.Title,
			Text:       item.Text,
			CreateTime: item.CreateTime,
			UpdateTime: item.UpdateTime,
		}
	}

	return response.GetUserSolutionListResp{
		Response:  response.CreateResponse(constanct.SuccessCode),
		Solutions: &solutions,
	}, nil
}

func AddUsersRange(ctx *gin.Context, req request.AddUsersRangeReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	resp := response.AddUsersResp{}
	resp.CreateNumber = 0
	resp.Data = make([]response.AddUsersItem, 0)
	if req.Password == nil || *req.Password == "" {
		req.Password = new(string)
		*req.Password = "123456"
	}
	for idx := 1; idx <= req.Number; idx++ {
		UID := fmt.Sprintf("%s%02d", req.Prefix, idx)
		err := models.CreateUser(ctx, &dao.User{
			UID:    UID,
			Uname:  UID,
			Pass:   *req.Password,
			School: req.School,
		})

		if err != nil {
			logger.Errorf("call CreateUser failed,UID=%+v,err=%s", UID, err.Error())
			continue
		} else {
			resp.CreateNumber += 1
			usersItem := response.AddUsersItem{
				UID:      UID,
				Uname:    UID,
				Password: *req.Password,
				School:   req.School,
			}
			resp.Data = append(resp.Data, usersItem)
		}
	}
	resp.Response = response.CreateResponse(constanct.SuccessCode)
	return resp, nil
}

func AddUsers(ctx *gin.Context, req *request.AddUsersReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	resp := response.AddUsersResp{}
	resp.CreateNumber = 0
	resp.Data = make([]response.AddUsersItem, 0)
	for _, item := range *req {
		user := dao.User{
			UID:   item.UID,
			Pass:  item.Pass,
			Uname: item.UserName,
		}
		err := models.CreateUser(ctx, &user)
		if err != nil {
			logger.Errorf("call CreateUser failed,user=%+v,err=%s", user, err.Error())
			continue
		}
		resp.CreateNumber += 1
		usersItem := response.AddUsersItem{
			UID:      user.UID,
			Uname:    user.Uname,
			Password: user.Pass,
			School:   user.School,
		}
		resp.Data = append(resp.Data, usersItem)
	}
	resp.Response = response.CreateResponse(constanct.SuccessCode)
	return resp, nil
}

func GetUsers(ctx *gin.Context, req *request.GetUsersReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	resp := response.GetUsersResp{}
	offset, limit := utils.GetPageInfo(req.Page, req.Limit)
	Users, err := models.GetUserList(ctx, req.Token, offset, limit)
	if err!=nil{
		logger.Debugf("GetUsetList error:%v",err)
		return nil,err
	}
	resp.Data=make([]response.GetUsersItem, len(Users))
	for idx :=range Users{
		user:=&Users[idx]
		resp.Data[idx]=response.GetUsersItem{
			Classes: user.Classes,
			School: user.School,
			Uname: user.Uname,
			UID: user.UID,
			Major: user.Major,
			Year: user.Year,
		}
	}
	resp.Response = response.CreateResponse(constanct.SuccessCode)
	return resp, nil
}

func GetUserStatusInfo(ctx *gin.Context, req request.UserStatusInfoReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	bigTime := time.Now() // 获取当前时间
	resp := response.UserStatusInfoResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}
	resp.Data = make([]response.UserStatusInfoItem, 0)
	switch req.Type {
	case constanct.Momth:
		{
			bigTime = bigTime.AddDate(0, -req.Time, 0)
		}
	case constanct.Year:
		{
			bigTime = bigTime.AddDate(-req.Time, 0, 0)
		}
	default:
		{
			bigTime = bigTime.AddDate(0, -6, 0)
		}
	}
	submit := dao.Submit{
		UID:    req.UID,
		Result: req.Result,
	}
	submits, err := models.GetUserStatusInfo(ctx, submit, bigTime.Unix())
	if err != nil {
		logger.Errorf("call GetUserStatusInfo failed, req=%+v,err=%s", utils.Sdump(req), err.Error())
		return nil, err
	}
	for _, submit := range submits {
		temp := response.UserStatusInfoItem{
			PID:        submit.PID,
			Result:     submit.Result,
			SubmitTime: submit.SubmitTime,
		}
		resp.Data = append(resp.Data, temp)
	}

	return resp, nil
}

func CodeForceBind(ctx *gin.Context, req request.CodeForceBindReq) (interface{}, error) {
	req.CodeForcePass = strings.Trim(req.CodeForcePass, " ")
	req.CodeForceUser = strings.Trim(req.CodeForceUser, " ")
	if len(req.CodeForceUser) == 0 {
		return constanct.USER_CFBIND_UserEmptyCode, errors.New("user empty")
	}
	cj := originJudged.CodeForceJudge{
		Headers: originJudged.CfHeaders,
		JudgeUser: &originJudged.CFJudgeUser{
			OriginJudgeUser: originJudged.OriginJudgeUser{
				ID:       req.CodeForceUser,
				Password: req.CodeForcePass,
				Cookies:  make(map[string]string, 0),
			},
		},
	}
	err := cj.Login()
	if err != nil {
		return constanct.USER_CFBIND_PassErrorCode, errors.New("pass error")
	}
	user := dao.User{
		UID:           middlewares.GetUid(ctx),
		CodeForceUser: req.CodeForceUser,
	}
	err = mysqldao.UpdateUserByUID(ctx, &user)
	if err != nil {
		return constanct.ServerErrorCode, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func AtcoderBind(ctx *gin.Context, req *request.AtcoderBindReq) (interface{}, error) {
	req.AtcoderPass = strings.TrimSpace(req.AtcoderPass)
	req.AtcoderUser = strings.TrimSpace(req.AtcoderUser)
	if len(req.AtcoderUser) == 0 {
		return response.CreateResponse(constanct.USER_ATBIND_UserEmptyCode), nil
	}
	user := dao.User{
		UID:         middlewares.GetUid(ctx),
		AtcoderUser: req.AtcoderUser,
	}
	aj := originJudged.AtCoderJudge{
		Headers: originJudged.AtcoderHeaders,
		JudgeUser: &originJudged.ATcoderJudgeUser{
			OriginJudgeUser: originJudged.OriginJudgeUser{
				ID:       req.AtcoderUser,
				Password: req.AtcoderPass,
				Cookies:  make(map[string]string, 0),
			},
		},
	}
	err := aj.Login(ctx)
	if err != nil {
		return response.CreateResponse(constanct.USER_ATBIND_FAILED), nil
	}
	err = mysqldao.UpdateUserByUID(ctx, &user)
	if err != nil {
		return nil, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func NowcoderBind(ctx *gin.Context, req *request.NowcoderBindReq) (interface{}, error) {
	user := dao.User{
		UID:          middlewares.GetUid(ctx),
		NowcoderUser: req.NowcoderUser,
	}
	err := mysqldao.UpdateUserByUID(ctx, &user)
	if err != nil {
		return nil, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func PasswordForget(ctx *gin.Context, req *request.PasswordForgetReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	email := strings.TrimSpace(req.Email)
	status, err := rediscache.GetEmailForgetPassFromRDB(ctx, email)
	if err != nil {
		logger.Errorf("call GetEmailForgetPassFromRDB failed,req.UID=%v,req.Code,err=%v", req.Email, err.Error())
		return constanct.ServerErrorCode, err
	} else if status != "1" {
		return constanct.AUTH_NOT_EMAIL_VERIFY, err
	}
	if err := rediscache.DelEmailForgetToRDB(ctx, email); err != nil {
		logger.Errorf("call DelEmailCodeToRDB failed,req.Email=%v,err=%v", req.Email, err.Error())
		return constanct.ServerErrorCode, err
	}
	user := dao.User{
		Email: req.Email,
	}
	if !models.IsUserExistByEmail(ctx, &user) {
		return constanct.USER_INFO_UIDNotExistCode, errors.New("user not exist")
	}
	AdminChangeUser(ctx, &request.AdminChangeUserReq{
		Email:    user.Email,
		Password: req.NewPassword,
	})
	return response.CreateResponse(constanct.SuccessCode), nil
}

func AdminChangeUser(ctx *gin.Context, req *request.AdminChangeUserReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	if req.UID != "" {
		user := dao.User{
			UID: req.UID,
		}
		ok := models.IsUserExistByUID(ctx, &user)
		if !ok {
			return response.CreateResponse(constanct.AUTH_LOGIN_UIDNotExistCode), nil
		}
		err := models.FindUserByUID(ctx, &user)
		if err != nil {
			logger.Errorf("call FindUserByUID failed,UID=%v err=%v", req.UID, err.Error())
			return response.CreateResponse(constanct.ServerErrorCode), err
		}
		if req.Email != "" {
			user.Email = req.Email
		} else {
			user.Pass, err = utils.MD5EnCode(user.UID, req.Password)
			if err != nil {
				logger.Errorf("call MD5EnCode failed,param=%v err=%v", utils.Sdump(req), err.Error())
				return response.CreateResponse(constanct.ServerErrorCode), err
			}
		} //通过UID改密码/邮箱
		err = mysqldao.UpdateUserByUID(ctx, &user)
		if err != nil {
			logger.Errorf("call UpdateUserByUID failed,param=%v err=%v", utils.Sdump(user), err.Error())
			return response.CreateResponse(constanct.ServerErrorCode), err
		}
		return response.CreateResponse(constanct.SuccessCode), nil
	}
	if req.Email != "" {
		user := dao.User{
			Email: req.Email,
		}
		ok := models.IsUserExistByEmail(ctx, &user)
		if !ok {
			return response.CreateResponse(constanct.AUTH_LOGIN_UIDNotExistCode), nil
		}
		err := models.FindUserByEmail(ctx, &user)
		if err != nil {
			logger.Errorf("call FindUserByEmail failed,UID=%v err=%v", req.Email, err.Error())
			return response.CreateResponse(constanct.ServerErrorCode), err
		}

		// if req.UID!=""{
		// 	user.UID = req.UID
		// 	err = mysqldao.UpdateUserByEmail(ctx, &user)//因为改变了主键，不能合并~
		// 	if err != nil {
		// 		logger.Errorf("call UpdateUserByEmail failed,param=%v err=%v", utils.Sdump(user), err.Error())
		// 		return response.CreateResponse(constanct.ServerErrorCode), err
		// 	}//这一块是到达不了的，但是放在这里吧，后面可以直接用
		// }else{
		user.Pass, err = utils.MD5EnCode(user.UID, req.Password)
		if err != nil {
			logger.Errorf("call MD5EnCode failed,param=%v err=%v", utils.Sdump(req), err.Error())
			return response.CreateResponse(constanct.ServerErrorCode), err
		}
		err = mysqldao.UpdateUserByUID(ctx, &user) //用主键会快一点
		if err != nil {
			logger.Errorf("call UpdateUserByUID failed,param=%v err=%v", utils.Sdump(user), err.Error())
			return response.CreateResponse(constanct.ServerErrorCode), err
		}
		// }
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func VerifyEmail(ctx *gin.Context, req *request.VerifyEmailReq) (interface{}, error) { //验证邮箱
	logger := utils.GetLogInstance()
	user:=dao.User{
		Email: req.Email,
	}
	err:=mysqldao.SelectUserByEmail(ctx,&user)
	if err!=nil{
		return response.CreateResponse(constanct.EMAIL_NOT_EXIST),nil
	}
	if req.Uname==""{
		req.Uname=user.Uname
	}
	if req.Method == request.Link {
		token := ctx.GetHeader("Authorization")
		if token == "" {
			logger.Error("token is empty")
			return response.CreateResponse(constanct.AUTH_Token_EmptyCode), nil
		}
		err := utils.EmailVerifyByLink(req.Uname, token, req.Email, rediscache.EmailUrlVerifyPath)//TODO: 这里有漏洞，会被知道构造方式？这样可能没有验证就直接修改了,加上随机值，存redis？
		logger.Debugf("EmailUrlVerifyPath:%v",rediscache.EmailUrlVerifyPath)
		if err != nil {
			logger.Errorf("call EmailVerifyByLink failed,param=%+v err=%v", utils.Sdump(req), err.Error())
			return constanct.AUTH_EMAIL_VERIFY_FAILED, err
		}
		return response.CreateResponse(constanct.SuccessCode), nil
	}
	if req.Method == request.Code {
		code := utils.GenRandCode(6)
		if ttl, err := rediscache.GetEmailCodeTTLFromRDB(ctx, req.Email,req.Type); err != nil {
			logger.Errorf("call GetEmailCodeTTLFromRDB failed,param=%+v err=%v", utils.Sdump(req), err.Error())
			return constanct.AUTH_EMAIL_VERIFY_FAILED, err
		} else if ttl > time.Minute*14 {
			return constanct.EMAIL_CODE_EXIST, errors.New("send the verification code repeatedly")
		}
		err := utils.EmailVerifyByCode(req.Uname, req.Email, code)
		if err != nil {
			logger.Errorf("call EmailVerifyByCode failed,param=%+v err=%v", utils.Sdump(req), err.Error())
			return constanct.AUTH_EMAIL_VERIFY_FAILED, err
		}
		err = rediscache.SaveEmailCodeToRDB(ctx, req.Email,req.Type, code)
		if err != nil {
			logger.Errorf("call SaveEmailCodeToRDB failed,param=%+v err=%v", utils.Sdump(req), err.Error())
			return constanct.EMAIL_CODE_STORE_FAILED, err
		}
		return response.CreateResponse(constanct.SuccessCode), nil
	}
	return response.CreateResponse(constanct.EMAIL_CODE_TYPE_ERROR), nil
}

func VerifyEmailURL(ctx *gin.Context, token string, email string) (interface{}, error) {
	logger := utils.GetLogInstance()
	claims, err := middlewares.ParseToken(token)
	if err != nil {
		logger.Errorf("call ParseToken failed,token=%v,err=%v", token, err.Error())
		return constanct.AUTH_Token_InvalidCode, nil
	}
	ok := models.UpdateUserEmail(ctx, claims.UserID, email)
	if ok != nil {
		logger.Errorf("call UpdateUserEmail failed,token=%v,err=%v", token, ok.Error())
		return constanct.AUTH_EMAIL_UPDATE_FAILED, nil
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func VerifyEmailCode(ctx *gin.Context, req *request.CodeVerifyReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	code, err := rediscache.GetEmailCodeFromRDB(ctx, req.Email,req.Type)
	if err != nil {
		logger.Errorf("call GetEmailCodeFromRDB failed,req.UID=%v,req.Code,err=%v", req.UID, err.Error())
		return constanct.ServerErrorCode, err
	} else if code == "" {
		return constanct.EMAIL_CODE_NOTEXIST, errors.New("code is not exist")
	} else if code != req.Code {
		logger.Infof("your code:%v ,code:%v", req.Code, code)
		return constanct.EMAIL_CODE_ERROR, errors.New("code is incorrect")
	}
	switch req.Type {
	case request.Register:
		ok := models.IsUserExistByUID(ctx, &dao.User{UID: req.UID})
		if ok {
			return constanct.AUTH_REGISTER_UIDExistCode, errors.New("uid is existed")
		}
		rediscache.SaveEmailRegisterToRDB(ctx, req.UID, req.Email)
	case request.ForgetPass:
		rediscache.SaveEmailForgetPassToRDB(ctx, req.Email)
	case request.Login:
		rediscache.SaveEmailLoginPassToRDB(ctx, req.Email)
	case request.ChangeEmail:
		rediscache.SaveEmailChangeToRDB(ctx, req.Email)
	default:
		logger.Errorf("incorrect Type:%v", req.Type)
		return constanct.ServerErrorCode, errors.New("incorrect Type")
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

func EmailChange(ctx *gin.Context, req *request.EmailChangeReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	email := strings.TrimSpace(req.Email)
	uid := middlewares.GetUid(ctx)
	status, err := rediscache.GetEmailChangeFromRDB(ctx, email)
	if err != nil {
		logger.Errorf("call GetEmailChangeFromRDB failed,req.UID=%v,req.Code,err=%v", req.Email, err.Error())
		return constanct.ServerErrorCode, err
	} else if status != "1" {
		return constanct.AUTH_NOT_EMAIL_VERIFY, err
	}
	if err := rediscache.DelEmailChangeToRDB(ctx, email); err != nil {
		logger.Errorf("call DelEmailChangeToRDB failed,req.Email=%v,err=%v", req.Email, err.Error())
		return constanct.ServerErrorCode, err
	}
	err = models.UpdateUserEmail(ctx, uid, req.Email)
	if err != nil {
		logger.Errorf("call UpdateUserEmail failed,err=%v", err.Error())
		return constanct.AUTH_EMAIL_UPDATE_FAILED, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

// 授权，获取Code
func QQAuth(ctx *gin.Context) (interface{}, error) {
	config := utils.GetAuthQQConfInstance()
	authUrl := config.AuthCodeURL(utils.GenVeriey(6), oauth2.SetAuthURLParam("grant_type", "authorization_code"))
	return &response.QQAuthResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		URL:      authUrl,
	}, nil
}

// Code->Token->UserInfo
func QQInfo(ctx *gin.Context, req *request.QQInfoReq) (*response.QQInfoResp, error) {
	logger := utils.GetLogInstance()
	config := utils.GetAuthQQConfInstance()
	token, err := config.Exchange(ctx.Request.Context(), req.Code, oauth2.SetAuthURLParam("grant_type", "authorization_code"))
	if err != nil {
		logger.Errorf("call Exchange failed,err=%v", err.Error())
		return nil, err
	}
	client := config.Client(ctx.Request.Context(), token)
	resp, err := client.Get(config.RedirectURL)
	if err != nil {
		logger.Errorf("call Get failed,err=%v", err.Error())
		return nil, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		logger.Errorf("call ReadAll failed,err=%v", err.Error())
		return nil, err
	}
	var qqInfo response.QQInfoItem
	err = json.Unmarshal(body, &qqInfo)
	if err != nil {
		logger.Errorf("call Unmarshal failed,err=%v", err.Error())
		return nil, err
	}
	return &response.QQInfoResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		UserInfo: qqInfo,
	}, nil
}

// UserInfo->JWT Token
func QQLogin(ctx *gin.Context, QQ string) (interface{}, error) {
	logger := utils.GetLogInstance()
	user := models.GetUserByQQ(ctx, QQ)
	if user == nil {
		return response.CreateResponse(constanct.AUTH_LOGIN_UIDNotExistCode), errors.New("uid is not exist")
	}
	token, err := middlewares.GetToken(ctx, user.UID)
	if err != nil {
		logger.Errorf("call GetToken failed,err=%v", err.Error())
		return nil, err
	}
	return &response.QQLoginResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		Token:    token,
	}, nil
}

// UserInfo->QQ绑定
func QQBind(ctx *gin.Context, QQ string) (interface{}, error) {
	logger := utils.GetLogInstance()
	user := dao.User{
		UID: middlewares.GetUid(ctx),
		QQ:  QQ,
	}
	err := models.UpdateUserQQ(ctx, &user)
	if err != nil {
		logger.Errorf("call UpdateUserQQ failed,err=%v", err.Error())
		return constanct.ServerErrorCode, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

// AddGroup 添加组
func AddGroup(ctx *gin.Context, req *request.AddGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
    group := dao.Group{
        GroupName:  req.GroupName,
		GroupTask:  req.GroupTask,
        UID:  		UID,
        CreateTime: utils.GetNow(),
		InviteCode: utils.GenRandCode(6),
    }
    err := mysqldao.AddGroup(ctx, group)
    if err != nil {
        logger.Errorf("call AddGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err //如果error不为nil，应该增加错误信息 自定义错误码
    }
	err = mysqldao.FindGroup(ctx, &group)
	if err!=nil{
		logger.Errorf("call FindGroup Failed, err=%s", err.Error())
		return constanct.ServerErrorCode, err
	}
	newGroupUser := dao.GroupUser{
        GID:      group.GID,
        UID:      UID,
        JoinTime: utils.GetNow(),
		Role: 	  -1,
    }
    err = mysqldao.AddUserToGroup(ctx, newGroupUser)
    if err != nil {
        logger.Errorf("call AddUserToGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
    return response.AddGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		GID:      group.GID,
	},nil
}

// DeleteGroup 删除组
func DeleteGroup(ctx *gin.Context, req *request.DeleteGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	if groupUser.Role!=-1{
		return constanct.USER_GROUP_DELETE_FAILED.Return()
	}
    err = mysqldao.DeleteGroup(ctx, req.GID)
    if err != nil {
        logger.Errorf("call DeleteGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
    return response.DeleteGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}, nil
}

// EditGroup 编辑组
func EditGroup(ctx *gin.Context, req *request.EditGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
    group := dao.Group{
        GID:       req.GID,
        GroupName: req.GroupName,
        GroupTask: req.GroupTask,
    }
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	if groupUser.Role!=-1{
		return constanct.USER_GROUP_DELETE_FAILED.Return()
	}
    err = mysqldao.EditGroup(ctx, &group)
    if err != nil {
        logger.Errorf("call EditGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
    return response.EditGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}, nil
}

func GroupTransfer(ctx *gin.Context, req *request.GroupTransferReq)(interface{}, error){
	logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
		return constanct.ServerErrorCode, err
	}
	if groupUser.Role!=-1{
		return constanct.USER_GROUP_DELETE_FAILED.Return()
	}
	group,err:=mysqldao.GetGroup(ctx,req.GID)
	if err!=nil{
		logger.Errorf("call GetGroup Failed, err=%s", err.Error())
		return constanct.USER_GROUP_NOT_FOUND, err
	}
	another,err:= mysqldao.GetGroupUser(ctx, req.GID, req.UID)
	if err!=nil{
		logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
		return constanct.USER_GROUP_USER_NOT_FOUND, err
	}
	another.Role=-1
	group.UID= another.UID
	err=mysqldao.EditGroup(ctx,group)
	if err!=nil{
		logger.Errorf("call EditGroup Failed, err=%s", err.Error())
		return constanct.ServerErrorCode, err
	}
	err=mysqldao.UpdateGroupUserRole(ctx,another)
	if err!=nil{
		logger.Errorf("call UpdateGroupUserRole Failed, err=%s", err.Error())
		return constanct.ServerErrorCode, err
	}
	groupUser.Role=1
	err=mysqldao.UpdateGroupUserRole(ctx,groupUser)
	if err!=nil{
		logger.Errorf("call UpdateGroupUserRole Failed, err=%s", err.Error())
		return constanct.ServerErrorCode, err
	}
	return response.CreateResponse(constanct.SuccessCode), nil
}

// GetGroupList 获取组列表
func GetGroupList(ctx *gin.Context,req *request.GetListReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	offset, limit := utils.GetPageInfo(req.Page, req.Limit)
	UID:=middlewares.GetUid(ctx)
    groups, err := mysqldao.GetGroupList(ctx, UID ,offset, limit)
    if err != nil {
        logger.Errorf("call GetGroupList Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	groupList:=make([]response.GetGroupListItem,len(*groups))
	for idx, group := range *groups {
		// logger.Debugf("group:%+v", utils.Sdump(group))
		groupUser, err := mysqldao.GetGroupUser(ctx, group.GID, UID)
		if err != nil {
			logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
			return constanct.ServerErrorCode, err
		}
		groupList[idx]=response.GetGroupListItem{
			GID:       group.GID,
			GroupName: group.GroupName,
			CreateTime: group.CreateTime,
			JoinTime:  groupUser.JoinTime,
			UID:       group.UID,
		}
		if groupUser.Role==-1{
			groupList[idx].InviteCode=group.InviteCode
		}
	}
    return response.GetGroupListResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		Groups:   &groupList,
	}, nil
}

// GetGroup 获取组信息
func GetGroup(ctx *gin.Context, GID int64) (interface{}, error) {
    logger := utils.GetLogInstance()
    group, err := mysqldao.GetGroup(ctx, GID)
    if err != nil {
        logger.Errorf("call GetGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	groupUserList, err := mysqldao.GetGroupUserList(ctx, GID)
	if err != nil {
		return constanct.ServerErrorCode, err
	}
	var uids []string
	for _, user := range groupUserList {
		uids = append(uids, user.UID)
	}
	resp:=response.GetGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		GID:      group.GID,
		GroupName: group.GroupName,
		GroupTask: group.GroupTask,
		CreateTime: group.CreateTime,
		UID:       group.UID,
		MemberUIDs: uids,
	}
	if groupUser.Role==-1{
		resp.InviteCode=group.InviteCode
	}
    return resp, nil
}

// AddUserToGroup 添加用户到组
func AddUserToGroup(ctx *gin.Context, req *request.AddUserToGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return nil, err
    }
	if groupUser.Role!=-1{
		return constanct.USER_GROUP_DELETE_FAILED.Return()
	}
    newGroupUser := dao.GroupUser{
        GID:      req.GID,
        UID:      req.UID,
        JoinTime: utils.GetNow(),
    }
    err = mysqldao.AddUserToGroup(ctx, newGroupUser)
    if err != nil {
        logger.Errorf("call AddUserToGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
    return response.AddUserToGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}, nil
}

// DeleteUserFromGroup 从组中删除用户
func DeleteUserFromGroup(ctx *gin.Context, req *request.DeleteUserFromGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
	if groupUser.Role!=-1{
		return constanct.USER_GROUP_DELETE_FAILED.Return()
	}
    err = mysqldao.DeleteUserFromGroup(ctx, req.GID, req.UID)
    if err != nil {
        logger.Errorf("call DeleteUserFromGroup Failed, err=%s", err.Error())
        return constanct.ServerErrorCode, err
    }
    return response.DeleteUserFromGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}, nil
}

// JoinGroup 加入组
func JoinGroup(ctx *gin.Context, req *request.JoinGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
    group, err := mysqldao.GetGroupByInviteCode(ctx, req.InviteCode)
    if err != nil {
        logger.Errorf("call GetGroupByInviteCode Failed, err=%s", err.Error())
        return nil, err
    }
    groupUser := dao.GroupUser{
        GID:      group.GID,
        UID:      middlewares.GetUid(ctx),
        JoinTime: utils.GetNow(),
		Role: 	  1,
    }
    err = mysqldao.AddUserToGroup(ctx, groupUser)
    if err != nil {
        logger.Errorf("call AddUserToGroup Failed, err=%s", err.Error())
        return nil, err
    }
    return response.JoinGroupResp{
		Response: response.CreateResponse(constanct.SuccessCode),
	}, nil
}

// QuitGroup 退出组
func QuitGroup(ctx *gin.Context, req *request.QuitGroupReq) (interface{}, error) {
    logger := utils.GetLogInstance()
	UID:=middlewares.GetUid(ctx)
	groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
    if err != nil {
        logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
        return nil, err
    }
	if groupUser.Role!=-1{
		err = mysqldao.DeleteUserFromGroup(ctx, req.GID,UID)
    	if err != nil {
        	logger.Errorf("call DeleteUserFromGroup Failed, err=%s", err.Error())
        	return nil, err
    	}
		return response.QuitGroupResp{
			Response: response.CreateResponse(constanct.SuccessCode),
		}, nil
	}else{
		return  constanct.USER_GROUP_USER_QUIT_FAILED.Return()
	}
}

func GetGroupTrace(ctx *gin.Context, req *request.GetGroupTraceReq) (interface{}, error) {
    logger := utils.GetLogInstance()
    var groupUserList []dao.GroupUser
	group, err := mysqldao.GetGroup(ctx, req.GID)
	if err != nil {
		return constanct.USER_GROUP_NOT_FOUND.Return()
	}
    if len(req.UIDs)==0 {
        UID := middlewares.GetUid(ctx)
        groupUser, err := mysqldao.GetGroupUser(ctx, req.GID, UID)
        if err != nil {
            logger.Errorf("call GetGroupUser Failed, err=%s", err.Error())
            return constanct.ServerErrorCode, err
        }
        if groupUser.Role != -1 {
            return constanct.USER_GROUP_USER_NOT_AUTH.Return()
        }
        groupUserList, err = mysqldao.GetGroupUserList(ctx, req.GID)
        if err != nil {
            return constanct.ServerErrorCode, err
        }
    }else{
		for _,uid:=range req.UIDs{
			groupUserList = append(groupUserList, dao.GroupUser{
				UID: uid,
			})
		}
	}
	groupSubmit, err := mysqldao.GetGroupSubmit(ctx, &groupUserList, group)
	if err != nil {
		logger.Errorf("call GetGroupSubmit Failed, err=%s", err.Error())
		return nil,nil
	}
	usersTrace := make(map[string]response.GetUserGroupTraceItem)
	for _, submit := range *groupSubmit {
		// logger.Debugf("[%v]:%v",submit.SID,submit.UID)
		traceItem,exist := usersTrace[submit.UID]
		if !exist {
			traceItem = response.GetUserGroupTraceItem{
				CIDTrace: []response.GroupCIDTraceItem{},
				LIDTrace: []response.GroupLIDTraceItem{},
				PIDTrace: []response.GroupPIDTraceItem{},
			}
		}
		if submit.CID != -1 {
			traceItem.CIDTrace = append(traceItem.CIDTrace, response.GroupCIDTraceItem{
				CID: submit.CID,
				PID: submit.PID,
				SID: submit.SID,
			})
		} else if submit.LID != -1 {
			traceItem.LIDTrace = append(traceItem.LIDTrace, response.GroupLIDTraceItem{
				LID: submit.LID,
				PID: submit.PID,
				SID: submit.SID,
			})
		} else {
			traceItem.PIDTrace = append(traceItem.PIDTrace, response.GroupPIDTraceItem{
				PID: submit.PID,
				SID: submit.SID,
			})
		}
		usersTrace[submit.UID] = traceItem
	}
	var user dao.User
	for _, groupUser := range groupUserList {
		user.UID = groupUser.UID
		mysqldao.SelectUserByUID(ctx, &user) // Error handling should be added
		traceItem := usersTrace[groupUser.UID]
		traceItem.UserName = user.Uname
		usersTrace[groupUser.UID] = traceItem
	}
	return response.GetGroupTraceResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		Trace: usersTrace,
	}, nil
}
